--机器人管理器
local skynet = require "skynet"
local cluster = require "skynet.cluster"
local filename = "robotmgr.lua"
local filelog = require "filelog"
local slottool = require "slottool"
local tabletool = require "tabletool"

require "brnnenum"

--初始化随机数
math.randomseed( os.time())
math.random()

--------------------------------

local RobotMgr = {
    CMD = {},
    handler = {},
    robotpool = {},         --机器人池，从robot节点获取500个，缓存在本节点
    robotinfo_list = {},    --运行中机器人的robotinfo数组
    max_robot_num = 200,    --最大机器人数
    min_robot_num = 50,     --最小机器人
    base_robot_num = 50,    --机器人基础值
    robot_inc_factor = 1,   --机器人增加系数
    sys_banker_infos = {},  --系统庄信息
    tableinfo_list = {},    --桌子信息列表
    cur_robot_num = 0,      --当前机器人数
}

---机器人起始rid，机器人rid为8位
local base_rid = 11111111

--机器人列表
local robot_list = {}

--是否运行机器人
local is_runrobot = true

--筹码权值表
local score_weights = {
    [1] = 500,
    [2] = 100,
    [3] = 5,
    [4] = 0,
    [5] = 0,
    [6] = 0,
    [7] = 0,
}

--特权位筹码权值表
local spseat_score_weights = {
    [1] = 20,       --1元
    [2] = 100,      --5元
    [3] = 50,       --10元
    [4] = 1,        --50元
    [5] = 0,        --100元
    [6] = 0,        --500元
    [7] = 0,        --1000元
}

--上庄权值表
local upbanker_weights = {
    [1] = 0,
    [2] = 0,
    [3] = 30,
    [4] = 40,
    [5] = 50,
    [6] = 80,
    [7] = 100,
}

--下注区域权值表
local betbtn_weights = {
    [1101] = 200,   --闲1赢
    [1102] = 200,   --闲2赢
    [1103] = 200,   --闲3赢
    [1104] = 200,   --闲4赢
}

-------------------

--获取机器人玩家数据
function RobotMgr.handler.gen_robotinfo(num)
    local status,result = skynet.pcall(cluster.call, "robotnode", ".router", "gen_robotinfo", num)
    if status and result then
        for _,robotinfo in pairs(result) do
            table.insert(RobotMgr.robotpool,robotinfo)
        end
        filelog.sys_info("--------gen robotinfo ok!----", #result)
    end
end

--保存机器人玩家数据
function RobotMgr.handler.save_robotinfo(robot_infos)
    local status,result = skynet.pcall(cluster.call, "robotnode", ".router", "save_robotinfo", robot_infos)
    if status and result then
        filelog.sys_info("-------save robotinfo ok!----", #robot_infos)
    else
        filelog.sys_info("-------save robotinfo failed!----", status, result)
    end
end

--获取机器人玩家数据
function RobotMgr.handler.get_robotinfo()
    if not RobotMgr.robotpool or #(RobotMgr.robotpool) < 1 then
        RobotMgr.handler.gen_robotinfo(450)
        return nil
    end
    local len = #(RobotMgr.robotpool)
    local idx = math.random(1,len)
    local robotinfo = RobotMgr.robotpool[idx]
    RobotMgr.robotpool[idx] = RobotMgr.robotpool[len]
    RobotMgr.robotpool[len] = nil

    return robotinfo
end

------------------------------------------------

--创建一个机器人
function RobotMgr.cretae_robot(obj)
    obj = obj or {}

    local robotinfo = RobotMgr.handler.get_robotinfo()
    if not robotinfo then
        return
    end

    local logo = robotinfo.logo or "1"
    local sex = robotinfo.sex or math.random(1,2)
    local rid = robotinfo.rid or math.random(111111,999999)
    local rolename = robotinfo.rolename or "_g" .. rid
    obj.roledata = {
        info = { 
            rolename = rolename,    --名字
            level = 99,             --等级
		    logo = logo,            --头像
		    sex = sex,              --性别
            rid = rid,
            },
        money = {
            diamond = 0,
            coin = 0,
            lock_coin = 0,
            lock_diamond = 0,
        },
        gps_addr = robotinfo.gps_addr,
        ip_addr = robotinfo.ip_addr,
        is_robot = true,
    }
    obj.rid = rid

    --随机diamond
    if math.random(1,3) > 1 then
        obj.roledata.money.diamond = math.random(1000, 10000) * 10
    else
        if math.random(1,3) == 1 then
            obj.roledata.money.diamond = math.random(40000, 80000) * 10
        else
            obj.roledata.money.diamond = math.random(10000, 80000) * 10
        end
    end

    --保存机器人
    robot_list[rid] = 0

    --保存robotinfo，方便回收
    RobotMgr.robotinfo_list[rid] = robotinfo

    return obj
end

--移除一个机器人
function RobotMgr.remove_robot(rid)
    if not robot_list[rid] then
        return
    end

    --在桌子内，让机器人离桌
    if robot_list[rid] ~= 0 then
        local result = skynet.call(robot_list[rid], "lua", "request", "leavetable", rid, {}, {})   --尝试离桌
        if not result or result.retcode ~= nil then
            skynet.send(robot_list[rid], "lua", "cmd", "delay_leave", rid)   --延迟离开，本局结束再离桌
        end
    else
        RobotMgr.delete_robot(rid)
    end
end

function RobotMgr.delete_robot(rid)
    if robot_list[rid] then
        local table_service = robot_list[rid]
        local cur_tableinfo = RobotMgr.tableinfo_list[table_service]
        if cur_tableinfo and cur_tableinfo.cur_robot_num then
            cur_tableinfo.cur_robot_num = cur_tableinfo.cur_robot_num - 1
        end
        RobotMgr.cur_robot_num = RobotMgr.cur_robot_num - 1
        table.insert( RobotMgr.robotpool, RobotMgr.robotinfo_list[rid])
        RobotMgr.robotinfo_list[rid] = nil
        robot_list[rid] = nil
    end
end

--添加机器人到桌子
function RobotMgr.add_robot_to_table(table_service, robot_num, is_upbanker)
    robot_num = robot_num or 1

    RobotMgr.tableinfo_list[table_service] = RobotMgr.tableinfo_list[table_service] or {}
    local cur_tableinfo = RobotMgr.tableinfo_list[table_service]
    local cur_robot_num = cur_tableinfo.cur_robot_num or 0
    local max_robot_num = cur_tableinfo.max_robot_num or RobotMgr.max_robot_num

    --超过最大机器人数，不添加
    if cur_robot_num + robot_num > max_robot_num then
        robot_num = max_robot_num - cur_robot_num
    end

    for i = 1,robot_num do
        local robot = RobotMgr.cretae_robot()
        if robot then
            if is_upbanker then
                robot.roledata.money.diamond = math.random(40000, 80000) * 10
            end
            --进桌
            local status,result = skynet.pcall(skynet.call, table_service, "lua", "request", "entertable", robot.rid, robot.roledata)
            RobotMgr.cur_robot_num = RobotMgr.cur_robot_num + 1
            if status and result.retcode == nil then
                robot_list[robot.rid] = table_service
                cur_tableinfo.cur_robot_num = (cur_tableinfo.cur_robot_num or 0) + 1
            else
                RobotMgr.remove_robot(robot.rid)
            end
        end
    end
    
end

--移除一些机器人
function RobotMgr.remove_robots(rids, num, table_service)
    num = num or #rids
    table_service = table_service or 0
    RobotMgr.tableinfo_list[table_service] = RobotMgr.tableinfo_list[table_service] or {}
    local cur_tableinfo = RobotMgr.tableinfo_list[table_service]
    local cur_robot_num = cur_tableinfo.cur_robot_num or 0

    --低于最小机器人数，不离桌
    if cur_robot_num - num < RobotMgr.min_robot_num then
        num = cur_robot_num - RobotMgr.min_robot_num
    end

    if num <= 0 then
        return
    end

    local cnt = 0
    for _,rid in pairs(rids) do
        RobotMgr.remove_robot(rid)
        cnt = cnt + 1
        if cnt == num then
            break
        end
    end
end

--移除所有机器人
function RobotMgr.remove_allrobot(is_force)
    if is_force then
        for rid,v in pairs(robot_list) do
            RobotMgr.delete_robot(rid)
        end
    else
        for rid,v in pairs(robot_list) do
            RobotMgr.remove_robot(rid)
        end
    end
end

--机器人下注
function RobotMgr.robot_do_bet(rbt_list, bet_btn_list, base_score_list, bet_time, sp_rids)
    --处理下注
    local function handle_bet(rid, bs_list, score_index, id, table_service, bet_cnt)
        local requestmsg = {
            action_type = EBRNNActionType.ACTION_TYPE_CHANGE_SCORE,
            base_score_index = score_index,
        }
        skynet.call(table_service, "lua", "request", "doaction", rid, {}, requestmsg)

        local total_delay = 0
        local cur_score = bs_list[score_index]
        for i = 1,bet_cnt do
            local msg = {
                bet_item_id = id,
                bet_score = cur_score,
                action_type = EBRNNActionType.ACTION_TYPE_BET,
            }
            skynet.send(table_service, "lua", "request", "doaction", rid, {}, msg)
            --延迟100~300ms
            local dy = math.random(1,3)
            total_delay = total_delay + dy
            skynet.sleep(dy * 10)
        end

        return total_delay
    end
    
    --下注
    local function do_bet(rid, betbtn_list, bs_list, bet_time, is_special)
        local total_tm = 0
        local table_service = robot_list[rid]
        local score_total_w = slottool.calculate_total_weight(score_weights)
        local bet_total_w = slottool.calculate_total_weight(betbtn_weights)

        --特权位固定下注区域
        local sp_bet_id = nil
        if is_special then
            local bet_id_list = {1101, 1102, 1103, 1104} --下闲1，闲2，闲3,闲4
            local r = math.random(1,4)
            sp_bet_id = bet_id_list[r]

            --特权延时1~3s再下注
            local delay = math.random(1,3)
            total_tm = total_tm + delay * 10
            skynet.sleep(delay * 100)
        end

        bet_time = bet_time * 10    --单位转化为100ms
        while bet_time - total_tm >= 10 do
            --随机下3~6注
            local bet_cnt = math.random(3,5)

            --随机底注
            local score_index = 1
            if is_special then
                bet_cnt = math.random(3,5)
                score_index = slottool.get_random_result_by_weightlist(spseat_score_weights)
            else
                score_index = slottool.get_random_result_by_weightlist(score_weights,score_total_w)
            end

            --随机下注项
            local id = sp_bet_id
            if not is_special or not id then
                id = slottool.get_random_result_by_weightlist(betbtn_weights,bet_total_w)
            end

            --下注
            total_tm = total_tm + handle_bet(rid, bs_list, score_index, id, table_service, bet_cnt)

            --随机延时0.5~1s
            local dy = math.random(5,10) / 10
            if is_special then
                dy = dy * 4
            end
            total_tm = total_tm + math.floor(dy * 10)
            skynet.sleep( math.floor(dy * 100))
        end
    end

    local num = 0
    local total = #(rbt_list)
    sp_rids = sp_rids or {} 
    for i,rid in pairs(rbt_list) do
        local is_special = nil
        if sp_rids[rid] then
            is_special = true
        end
        if num < 20 or is_special then
            if not is_special and total > 25 and (num + total - i) > 20 then
                if math.random(1,2) == 1 then
                    skynet.fork(do_bet, rid, bet_btn_list, base_score_list, bet_time, is_special)
                    num = num + 1
                end
            else
                skynet.fork(do_bet, rid, bet_btn_list, base_score_list, bet_time, is_special)
                num = num + 1
            end
        end
    end
end

--
--机器人上庄
--
function RobotMgr.robot_up_banker(rbt_list, max_robot_num, sys_banker_num, is_force)
    sys_banker_num = sys_banker_num or 0
    if sys_banker_num > 7 then
        sys_banker_num = 7
    end

    local num = 0
    local w_list = nil
    local failed_w = 100
    local w = upbanker_weights[7] or 0
    
    failed_w = failed_w - w
    w_list = {[0] = failed_w, [1] = w}
    for i,rid in pairs(rbt_list) do
        --随机概率上庄
        local r = math.random(1,2)
        if r == 1 or is_force then
            num = num + 1
            local is_ok = slottool.get_random_result_by_weightlist(w_list)
            if is_ok == 1 then
                skynet.pcall(skynet.call,robot_list[rid], "lua", "request", "doaction", rid, {}, {action_type = EBRNNActionType.ACTION_TYPE_UP_BANKER})
            end
            if num >= max_robot_num then
                break
            end
            local delay = math.random(1,3) * 200
            skynet.sleep(delay)
        end
    end
end

--
--更新游戏信息
--
function RobotMgr.update_gameinfo(bet_score_list, total_player_num, total_robot_num, table_service)
    local base_score_list = {}
    for score,cnt in pairs(bet_score_list) do
        table.insert(base_score_list,score)
    end
    table.sort(base_score_list)

	--[[
    local len = #(base_score_list)
    for idx,score in ipairs(base_score_list) do
        score_weights[idx] = 10 * (len - idx) + (bet_score_list[score] or 0)
    end
	]]

    --更新桌子机器人信息
    table_service = table_service or 0
    RobotMgr.tableinfo_list[table_service] = RobotMgr.tableinfo_list[table_service] or {}
    local cur_tableinfo = RobotMgr.tableinfo_list[table_service]
    cur_tableinfo.cur_robot_num = total_robot_num or 0
    
    --更新最大机器人数
    cur_tableinfo.max_robot_num = RobotMgr.base_robot_num + math.floor(RobotMgr.robot_inc_factor * total_player_num)
    if cur_tableinfo.max_robot_num > 200 then
        cur_tableinfo.max_robot_num = 200
    end
end

---------------------------------------------------

--
--创建系统庄信息
--
function RobotMgr.CMD.gen_system_banker_info()
    local status,result = skynet.pcall(cluster.call, "robotnode", ".router", "gen_robotinfo", 1)
    if status and result and result[1] then
        table.insert(RobotMgr.sys_banker_infos,tabletool.deepcopy(result[1]))
        return result[1]
    end
end

--设置机器人状态
function RobotMgr.CMD.set_game_robot_state(is_run)
    if is_run then
        is_runrobot = true
    else
        is_runrobot = false
        --踢掉所有机器人
        RobotMgr.remove_allrobot()
    end
end

--获得机器人状态
function RobotMgr.CMD.get_game_robot_state()
    return is_runrobot
end

--获得机器人数目
function RobotMgr.CMD.get_game_robot_num()
    return RobotMgr.cur_robot_num
end

--设置游戏机器人数量
function RobotMgr.CMD.set_game_robot_num(base_num, inc_factor, min_num)
    base_num = tonumber(base_num) or 20
    inc_factor = tonumber(inc_factor) or 0.2
    min_num = tonumber(min_num or 10) or 10
    if base_num >= 0 then
        RobotMgr.base_robot_num = base_num
    end
    if inc_factor > 0 then
        RobotMgr.robot_inc_factor = inc_factor
    end
    if min_num >= 0 then
        RobotMgr.min_robot_num = min_num
    end
end

--重置机器人
function RobotMgr.CMD.reset_robots()
    --先删除所有机器人
    RobotMgr.remove_allrobot()
    --延时30s，等机器人离桌
    skynet.sleep(3000)
    --再删一次，防止遗漏
    RobotMgr.remove_allrobot(true)
    --插入系统庄信息
    for _,banker_info in pairs(RobotMgr.sys_banker_infos) do
        table.insert(RobotMgr.robotpool,banker_info)
    end
    --保存机器人数据
    RobotMgr.handler.save_robotinfo(RobotMgr.robotpool)
end

-------------

--初始化
local function init()
    RobotMgr.handler.gen_robotinfo(450)
end

------------------

skynet.start(function()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = RobotMgr.CMD[cmd]
        if f then
            skynet.retpack(f(...))
        elseif is_runrobot then
            f = RobotMgr[cmd]
            if f then
                skynet.retpack(f(...))
            else
                skynet.retpack()
            end
        else
            skynet.retpack()
        end
    end)
    init()
end)
